﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Orchard.Collections;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Core.Contents.Settings;
using Orchard.ContentManagement;
using Orchard.Indexing;
using Orchard.Localization;
using Orchard.Mvc;
using Orchard.Mvc.Html;
using Orchard.UI.Navigation;
using SchoolPointe.Menus.Enums;
using SchoolPointe.Menus.Models;
using SchoolPointe.Menus.ViewModels;
using SchoolPointe.RelatedContent.Models;
using SchoolPointe.RelatedContent.Services;

namespace SchoolPointe.Menus.Services
{
    public class MenuService : IMenuService
    {
        private readonly IContentManager _contentManager;
        private readonly IIndexManager _indexManager;
        private readonly IRelatedContentService _relatedContentService;

        public MenuService(IContentManager contentManager, IIndexManager indexManager, IRelatedContentService relatedContentService)
        {
            _contentManager = contentManager;
            _indexManager = indexManager;
            _relatedContentService = relatedContentService;
        }

        ISearchBuilder Search()
        {
            return _indexManager.HasIndexProvider()
                ? _indexManager.GetSearchIndexProvider().CreateSearchBuilder("Search")
                : new NullSearchBuilder();
        }

        public IEnumerable<MenuViewModel> GetMenus()
        {
            return _contentManager.Query<BetterMenuPart, BetterMenuPartRecord>().List().Select(m => new MenuViewModel(m));
        }

        public IEnumerable<INavigationProvider> GetNavigationProviders()
        {
            return _contentManager.Query<BetterMenuPart, BetterMenuPartRecord>().List().Select(menu => new NavigationProvider(menu, (builder, menuPart) => BuildNavigation(builder, menu.As<RelatedContentPart>())));
        }

        private void BuildNavigation(NavigationBuilder builder, RelatedContentPart parent, string parentPosition = "")
        {
            var menuItems = _relatedContentService
                .GetRelatedItems(parent, "menu-items")
                .Select(ri => _contentManager.Get<BetterMenuItemPart>(ri.Id))
                .OrderBy(mi => mi.SortOrder)
                .ToList();
            for (int i = 0; i < menuItems.Count(); i++)
            {
                var menuItem = menuItems[i];
                var text = new LocalizedString(HttpUtility.HtmlEncode(menuItem.Text));
                var position = parentPosition + i.ToString();                
                builder.Add(text, position, item =>
                    {
                        if (menuItem.MenuItemType == MenuItemType.CustomLink)
                            item.Url(menuItem.Url);
                        else
                        {
                            var metadata = _contentManager.GetItemMetadata(menuItem.RelatedItem.Value);
                            if (metadata.DisplayRouteValues != null)
                            {                                
                                item.Action(metadata.DisplayRouteValues);
                            }

                        }

                        var displayShape = _contentManager.BuildDisplay(menuItem);
                        foreach (var cssClass in displayShape.Classes)
                        {
                            item.AddClass(cssClass);
                        }
                        if (displayShape.Attributes.ContainsKey("id"))
                            item.IdHint(displayShape.Attributes["id"]);

                        BuildNavigation(item, menuItem.As<RelatedContentPart>(), position + ".");
                    });                
            }            
        }

        public IEnumerable<ContentTypeDefinition> GetPossibleContentTypes()
        {
            return _contentManager
                .GetContentTypeDefinitions()
                .Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable && ctd.Parts.Any(p => p.PartDefinition.Name == "AutoroutePart"))
                .AsEnumerable();
        }

        public IPageOfItems<T> SearchForContentItems<T>(string query, int page, int? pageSize, string[] searchFields, string[] contentTypes, Func<ISearchHit, T> shapeResult)
        {
            if (string.IsNullOrWhiteSpace(query))
                return new PageOfItems<T>(Enumerable.Empty<T>());

            var searchBuilder = Search().Parse(searchFields, query);

            foreach (var contentType in contentTypes)
            {
                searchBuilder.WithField("type", contentType).ExactMatch().AsFilter();   
            }            

            var totalCount = searchBuilder.Count();
            if (pageSize != null)
                searchBuilder = searchBuilder
                    .Slice((page > 0 ? page - 1 : 0) * (int)pageSize, (int)pageSize);

            var searchResults = searchBuilder.Search();

            var pageOfItems = new PageOfItems<T>(searchResults.Select(shapeResult))
            {
                PageNumber = page,
                PageSize = pageSize != null ? (int)pageSize : totalCount,
                TotalItemCount = totalCount
            };

            return pageOfItems;
        }
    }
}